using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrchardCore.Data.EFCore;
using OrchardCore.Data.EFCore.Options;
using OrchardCore.Environment.Shell;
using OrchardCore.Data;

namespace OrchardCore.Data.EFCore.DbContext;

/// <summary>
/// OrchardCore DbContext基类
/// 提供OrchardCore应用程序中DbContext的基础实现
/// </summary>
/// <remarks>
/// 主要功能：
/// - 提供多租户支持
/// - 配置表前缀和架构
/// - 集成日志记录
/// - 支持配置选项
/// - 提供事务管理
/// </remarks>
public abstract class OrchardCoreDbContext : Microsoft.EntityFrameworkCore.DbContext, IOrchardCoreDbContext
{
    private readonly ShellSettings _shellSettings;
    private readonly EFCoreOptions _options;
    private readonly ILogger _logger;

    /// <summary>
    /// 获取数据库连接字符串
    /// </summary>
    public string ConnectionString => _shellSettings["ConnectionString"];

    /// <summary>
    /// 获取数据库提供程序名称
    /// </summary>
    public string ProviderName => _shellSettings["DatabaseProvider"];

    /// <summary>
    /// 获取租户名称
    /// </summary>
    public string TenantName => _shellSettings.Name;

    /// <summary>
    /// 获取表前缀
    /// </summary>
    public string TablePrefix => _shellSettings["TablePrefix"];

    /// <summary>
    /// 获取架构名称
    /// </summary>
    public string Schema => _shellSettings["Schema"];

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="options">DbContext选项</param>
    /// <param name="shellSettings">Shell设置</param>
    /// <param name="efCoreOptions">EF Core选项</param>
    /// <param name="logger">日志记录器</param>
    protected OrchardCoreDbContext(
        DbContextOptions options,
        ShellSettings shellSettings,
        IOptions<EFCoreOptions> efCoreOptions,
        ILogger logger)
        : base(options)
    {
        _shellSettings = shellSettings;
        _options = efCoreOptions.Value;
        _logger = logger;
    }

    /// <summary>
    /// 配置模型
    /// </summary>
    /// <param name="modelBuilder">模型构建器</param>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // 应用表前缀
        if (!string.IsNullOrEmpty(TablePrefix))
        {
            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {
                var tableName = entityType.GetTableName();
                if (!string.IsNullOrEmpty(tableName))
                {
                    entityType.SetTableName($"{TablePrefix}{tableName}");
                }
            }
        }

        // 应用架构
        if (!string.IsNullOrEmpty(Schema))
        {
            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {
                entityType.SetSchema(Schema);
            }
        }

        // 调用子类配置
        OnModelCreatingCore(modelBuilder);
    }

    /// <summary>
    /// 配置DbContext
    /// </summary>
    /// <param name="optionsBuilder">DbContext选项构建器</param>
    public virtual void Configure(DbContextOptionsBuilder optionsBuilder)
    {
        // 配置详细错误
        if (_options.EnableDetailedErrors)
        {
            optionsBuilder.EnableDetailedErrors();
        }

        // 配置敏感数据日志
        if (_options.EnableSensitiveDataLogging)
        {
            optionsBuilder.EnableSensitiveDataLogging();
        }

        // 移除 CommandTimeout 配置（EF Core 没有这个 API）

        // 配置变更跟踪
        if (!_options.EnableChangeTracking)
        {
            optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        }

        // 配置自动检测变更
        if (!_options.EnableAutoDetectChanges)
        {
            ChangeTracker.AutoDetectChangesEnabled = false;
        }

        // 移除 UseLazyLoadingProxies 配置（需要额外的包）
    }

    /// <summary>
    /// 初始化DbContext
    /// </summary>
    public virtual async Task InitializeAsync()
    {
        _logger.LogInformation("Initializing EF Core DbContext for tenant: {TenantName}", TenantName);

        try
        {
            // 确保数据库已创建
            await EnsureCreatedAsync();

            // 应用迁移
            if (_options.EnableAutoMigrations)
            {
                await MigrateAsync();
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to initialize EF Core DbContext for tenant: {TenantName}", TenantName);
            throw;
        }
    }

    /// <summary>
    /// 确保数据库已创建
    /// </summary>
    public virtual async Task EnsureCreatedAsync()
    {
        if (!await Database.CanConnectAsync())
        {
            await Database.EnsureCreatedAsync();
            _logger.LogInformation("Database created for tenant: {TenantName}", TenantName);
        }
    }

    /// <summary>
    /// 应用迁移
    /// </summary>
    public virtual async Task MigrateAsync()
    {
        if (Database.GetPendingMigrations().Any())
        {
            await Database.MigrateAsync();
            _logger.LogInformation("Migrations applied for tenant: {TenantName}", TenantName);
        }
    }

    /// <summary>
    /// 核心模型配置方法，由子类实现
    /// </summary>
    /// <param name="modelBuilder">模型构建器</param>
    protected abstract void OnModelCreatingCore(ModelBuilder modelBuilder);

    /// <summary>
    /// 保存更改
    /// </summary>
    /// <param name="acceptAllChangesOnSuccess">是否在成功时接受所有更改</param>
    /// <returns>保存的实体数量</returns>
    public override int SaveChanges(bool acceptAllChangesOnSuccess)
    {
        try
        {
            var result = base.SaveChanges(acceptAllChangesOnSuccess);
            _logger.LogDebug("Saved {Count} changes for tenant: {TenantName}", result, TenantName);
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to save changes for tenant: {TenantName}", TenantName);
            throw;
        }
    }

    /// <summary>
    /// 异步保存更改
    /// </summary>
    /// <param name="acceptAllChangesOnSuccess">是否在成功时接受所有更改</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>保存的实体数量</returns>
    public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
    {
        try
        {
            var result = await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
            _logger.LogDebug("Saved {Count} changes for tenant: {TenantName}", result, TenantName);
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to save changes for tenant: {TenantName}", TenantName);
            throw;
        }
    }
} 